<template>
  <div>
    <a-menu
      :openKeys.sync="openKeys"
      :selectedKeys="selectedKeys"
      mode="inline"
      :theme="$route.query.navTheme || 'dark'"
      :inlineCollapsed="collapsed"
    >
      <template v-for="item in menuInfo">
        <a-menu-item
          v-if="!item.children"
          :key="item.name"
          @click="() => $router.push({ name: item.name, query: $route.query })"
        >
          <a-icon v-if="item.meta.icon" :type="item.meta.icon" />
          <span>{{ item.meta.title }}</span>
        </a-menu-item>
        <sub-menu v-else :menu-info="item" :key="item.name" />
      </template>
    </a-menu>
  </div>
</template>

<script>
/*
 * recommend SubMenu.vue https://github.com/vueComponent/ant-design-vue/blob/master/components/menu/demo/SubMenu.vue
 * SubMenu1.vue https://github.com/vueComponent/ant-design-vue/blob/master/components/menu/demo/SubMenu1.vue
 * */
import SubMenu from "./SubMenu";

export default {
  name: "SiderMenu",
  components: {
    "sub-menu": SubMenu
  },
  created() {
    // console.log(this.$router)
    this.menuInfo = this.getRouterInfo(this.$router.options.routes);
    this.selectedKeys = this.selectedKeysMaps[this.$route.name];
    this.openKeys = this.openKeysMaps[this.$route.name];
    // console.log(this.openKeysMaps)
    // console.log(this.selectedKeysMaps)
    // console.log(this.menuInfo)
  },
  data() {
    return {
      collapsed: false,
      menuInfo: [],
      openKeys: [], //当前展开的 SubMenu 菜单项 key 数组
      selectedKeys: [], //当前选中的菜单项 key 数组
      openKeysMaps: {}, // 展开key对象map，key：路由name，value：该路由的所有父级路由name组成的数组
      selectedKeysMaps: {} // 选中key对象map，key：路由name，value：该自身路由name 或者其某一个父路由 name组成的数组
    };
  },
  watch: {
    "$route.path": function() {
      // 监听路由发生了变化，重新选择打开项和选中项
      this.selectedKeys = this.selectedKeysMaps[this.$route.name];
      this.openKeys = this.openKeys.length
        ? [...this.openKeys, ...this.openKeysMaps[this.$route.name]]
        : this.openKeysMaps[this.$route.name];
    }
  },
  methods: {
    toggleCollapsed() {
      this.collapsed = !this.collapsed;
    },
    /**
     * 获取左侧导航可以展示的路由数据
     * @param routes 当前路由各项数据组成的数组
     * @param parentKeys 父级路由name组成的数组，初始化一个空数组，表示第一次遍历调用时一级路由是没有父级路由的
     * @param parentSelectedKey 传入父级路由的name  字符串类型
     * @returns {Array} 返回可以展示的路由数组
     */
    getRouterInfo(routes, parentKeys = [], parentSelectedKey) {
      let menuData = [];
      let vm = this;
      routes.forEach(function(route) {
        let newItem = { ...route }; // 避免操作原对象
        delete newItem.children; // 先删除其子数组，1.可避免数组的引用对源对象造成一些bug，2.有一些子路由不展示，这里可以先删除，后面根据情况处理后再加回来
        if (!route.hideInMenu) {
          // 确定要展示的路由
          if (route.name && !route.children) {
            // 1.有name并且没有子路由的
            menuData.push(newItem);
            vm.openKeysMaps[route.name] = parentKeys; // 该路由name = 其所有父级路由的name组成的数组
            // 该路由name = 其自身路由name 或者 其可以在左侧导航显示的父级路由的name 组成的数组
            // （用于父级导航展示，隐藏了子级导航，但跳转到子级路由时依然要父级导航保持选中，所有要首先确定有没有传入父级路由key）
            vm.selectedKeysMaps[route.name] = [parentSelectedKey || route.name];
          } else if (route.name && route.children && route.hideChildrenInMenu) {
            // 这里仅为了获取openKeysMaps、selectedKeysMaps，
            // 但不使用其返会的menuData，因为这里是要隐藏子级导航的，但依然递归其子路由来获取完整的openKeysMaps、selectedKeysMaps
            vm.getRouterInfo(
              route.children,
              [...parentKeys, route.name],
              parentSelectedKey || route.name
            );
            // 2.有name且有子路由但是隐藏了子路由的  都表示只加入当前路由
            menuData.push(newItem);
          } else if (route.children && !route.hideChildrenInMenu) {
            // 3.有子路由但是没有隐藏其子路由的
            // 递归获取其子路由的数组后
            // 这里有子路由并且没有隐藏，所以这里的parentSelectedKey，可以不用传入，直接使用子路由自身的name就好
            newItem.children = [
              ...vm.getRouterInfo(route.children, [...parentKeys, route.name])
            ];
            // 如果当前路由有name则加入当前路由及其子路由，如果当前路由没有name，表示只加入其子路由
            route.name
              ? menuData.push(newItem)
              : menuData.push(...newItem.children);
          }
        }
      });
      return menuData;
    }
  }
};
</script>
